using System.Diagnostics;
using OracleInternal.Network;

namespace OracleInternal.Common
{
	internal class OraBufPool
	{
		internal string m_poolId;

		private OraBuf[] m_smallBufPooler;

		private OraBuf[] m_largeBufPooler;

		private object m_smallBufPoolerSync;

		private object m_largeBufPoolerSync;

		private object m_sduChangeSync;

		private int m_smallBufPoolerPos;

		private int m_largeBufPoolerPos;

		internal int m_smallBufSize;

		internal int m_largeBufSize;

		private int m_bufPoolerCapacity;

		public OraBufPool(int maxSubCacheSize)
		{
			m_poolId = GetHashCode().ToString();
			m_bufPoolerCapacity = maxSubCacheSize - 1;
			m_smallBufPooler = new OraBuf[m_bufPoolerCapacity + 1];
			m_largeBufPooler = new OraBuf[m_bufPoolerCapacity + 1];
			m_sduChangeSync = new object();
			m_smallBufPoolerSync = new object();
			m_largeBufPoolerSync = new object();
			m_smallBufPoolerPos = -1;
			m_largeBufPoolerPos = -1;
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				StackTrace stackTrace = new StackTrace();
				string name = stackTrace.GetFrame(2)!.GetMethod()!.Name;
				string name2 = stackTrace.GetFrame(2)!.GetMethod()!.ReflectedType!.Name;
				string text = $"(OBP.CTOR) (poolid:{m_poolId}) ({name2}.{name})";
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.BUF, OracleTraceClassName.OraBufPool, OracleTraceFuncName.ctor, text);
			}
		}

		public void Output(string method, int bufId, int key, int count)
		{
			StackTrace stackTrace = new StackTrace();
			string name = stackTrace.GetFrame(2)!.GetMethod()!.Name;
			string name2 = stackTrace.GetFrame(2)!.GetMethod()!.ReflectedType!.Name;
			string text = $"({method}) (poolid:{m_poolId}) (key:{key}) (bufid:{bufId}) (count:{count}) ({name2}.{name})";
			Trace.Write(OracleTraceLevel.Private, OracleTraceTag.BUF, OracleTraceClassName.OraBufPool, OracleTraceFuncName.Output, text);
		}

		internal void UpdateBufSizes(OracleCommunication oc)
		{
			lock (m_sduChangeSync)
			{
				if (m_smallBufSize == oc.m_sessionCtx.m_sessionDataUnit)
				{
					return;
				}
				int sessionDataUnit = oc.m_sessionCtx.m_sessionDataUnit;
				int num = sessionDataUnit * 4;
				if (sessionDataUnit != m_smallBufSize && sessionDataUnit != m_largeBufSize)
				{
					lock (m_smallBufPoolerSync)
					{
						while (m_smallBufPoolerPos >= 0)
						{
							m_smallBufPooler[m_smallBufPoolerPos] = null;
							m_smallBufPoolerPos--;
						}
					}
				}
				if (num != m_smallBufSize && num != m_largeBufSize)
				{
					lock (m_largeBufPoolerSync)
					{
						while (m_largeBufPoolerPos >= 0)
						{
							m_largeBufPooler[m_largeBufPoolerPos] = null;
							m_largeBufPoolerPos--;
						}
					}
				}
				m_smallBufSize = sessionDataUnit;
				m_largeBufSize = num;
			}
		}

		public OraBuf Get(int key, OracleCommunication oc, bool bReceive)
		{
			OraBuf oraBuf = null;
			int count = 0;
			if (key == m_smallBufSize)
			{
				if (m_smallBufPoolerPos >= 0)
				{
					lock (m_smallBufPoolerSync)
					{
						if (key == m_smallBufSize && m_smallBufPoolerPos >= 0)
						{
							oraBuf = m_smallBufPooler[m_smallBufPoolerPos];
							m_smallBufPooler[m_smallBufPoolerPos--] = null;
							count = m_smallBufPoolerPos + 1;
						}
					}
				}
			}
			else if (key == m_largeBufSize && m_largeBufPoolerPos >= 0)
			{
				lock (m_largeBufPoolerSync)
				{
					if (key == m_largeBufSize && m_largeBufPoolerPos >= 0)
					{
						oraBuf = m_largeBufPooler[m_largeBufPoolerPos];
						m_largeBufPooler[m_largeBufPoolerPos--] = null;
						count = m_largeBufPoolerPos + 1;
					}
				}
			}
			if (oraBuf == null)
			{
				oraBuf = new OraBuf(oc, key, bReceive);
			}
			else
			{
				oraBuf.ReInit(bReceive);
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Output("OBP.GET", oraBuf.m_id, key, count);
			}
			return oraBuf;
		}

		public OraBuf GetUninitialized(int key, OracleCommunication oc)
		{
			OraBuf oraBuf = null;
			int count = 0;
			if (key == m_smallBufSize)
			{
				if (m_smallBufPoolerPos >= 0)
				{
					lock (m_smallBufPoolerSync)
					{
						if (key == m_smallBufSize && m_smallBufPoolerPos >= 0)
						{
							oraBuf = m_smallBufPooler[m_smallBufPoolerPos];
							count = m_smallBufPoolerPos;
							m_smallBufPooler[m_smallBufPoolerPos--] = null;
						}
					}
				}
			}
			else if (key == m_largeBufSize && m_largeBufPoolerPos >= 0)
			{
				lock (m_largeBufPoolerSync)
				{
					if (key == m_largeBufSize && m_largeBufPoolerPos >= 0)
					{
						oraBuf = m_largeBufPooler[m_largeBufPoolerPos];
						count = m_smallBufPoolerPos;
						m_largeBufPooler[m_largeBufPoolerPos--] = null;
					}
				}
			}
			if (oraBuf == null)
			{
				oraBuf = new OraBuf(oc, key, ReceiveBuf: true);
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Output("OBP.GET", oraBuf.m_id, key, count);
			}
			return oraBuf;
		}

		public void Put(int key, OraBuf oraBuf)
		{
			int count = 0;
			if (oraBuf.m_size == m_smallBufSize)
			{
				if (m_smallBufPoolerPos < m_bufPoolerCapacity)
				{
					lock (m_smallBufPoolerSync)
					{
						if (m_smallBufPoolerPos < m_bufPoolerCapacity)
						{
							m_smallBufPooler[++m_smallBufPoolerPos] = oraBuf;
							count = m_smallBufPoolerPos + 1;
						}
					}
				}
			}
			else if (oraBuf.m_size == m_largeBufSize && m_largeBufPoolerPos < m_bufPoolerCapacity)
			{
				lock (m_largeBufPoolerSync)
				{
					if (m_largeBufPoolerPos < m_bufPoolerCapacity)
					{
						m_largeBufPooler[++m_largeBufPoolerPos] = oraBuf;
						count = m_smallBufPoolerPos + 1;
					}
				}
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Output("OBP.PUT", oraBuf.m_id, oraBuf.m_size, count);
			}
		}
	}
}
